/*
 * Copyright (C), 2015-2018
 * FileName: WebSocketHandler
 * Author:   zhao
 * Date:     2018/8/10 11:44
 * Description: websocket的消息处理
 * History:
 * <author>          <time>          <version>          <desc>
 * 作者姓名           修改时间           版本号              描述
 */
package com.loveprogrammer.base.network.channel.websocket;

import com.loveprogrammer.codec.MessageDecoder;
import com.loveprogrammer.constants.ConstantValue;
import com.loveprogrammer.listener.INetworkEventListener;
import com.loveprogrammer.pojo.StringMessage;
import com.loveprogrammer.utils.HttpResponseUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.websocketx.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * 〈一句话功能简述〉<br>
 * 〈websocket的消息处理〉
 *
 * @author zhao
 * @date 2018/8/10 11:44
 * @since 1.0.1
 */
@Component
@Scope("prototype")
public class WebSocketHandler extends SimpleChannelInboundHandler<Object> {

  // 查看是二进制模式 还是 protobuf模式

  @Autowired
  private INetworkEventListener listener;

  private WebSocketServerHandshaker handshaker;

  @Override
  protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
    if (msg instanceof FullHttpRequest) {
      // 传统的HTTP接入
      handleHttpMessage(ctx, msg);
    } else if (msg instanceof WebSocketFrame) {
      // WebSocket接入
      handleWebSocketMessage(ctx,(WebSocketFrame) msg);
    } else if (msg instanceof StringMessage) {
      // 这里已经通过WebSocketFrameToIMessageDecoder进行解码，这里基本上用不上
      listener.channelRead(ctx, (StringMessage) msg);
    }
  }

  /**
   * 处理WebSocket中的Http消息
   *
   * @param ctx 上下文
   * @param msg 消息
   */
  private void handleHttpMessage(ChannelHandlerContext ctx, Object msg) {
    // 传统的HTTP接入
    FullHttpRequest request = (FullHttpRequest) msg;

    // 如果HTTP解码失败，返回HHTP异常
    if (!request.decoderResult().isSuccess() || (!"websocket".equals(request.headers().get("Upgrade")))) {
      HttpResponseUtil.sendHttpResponse(ctx, request,
              new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
      return;
    }

    // 正常WebSocket的Http连接请求，构造握手响应返回
    WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
            "ws://" + request.headers().get(HttpHeaderNames.HOST), null, false);
    WebSocketServerHandshaker handshaker = wsFactory.newHandshaker(request);
    if (handshaker == null) { // 无法处理的websocket版本
      WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
    } else { // 向客户端发送websocket握手,完成握手
      handshaker.handshake(ctx.channel(), request);
    }
  }

  /**
   * 处理WebSocket中的WebSocket消息
   *
   * @param ctx 上下文
   * @param msg 消息
   */
  private void handleWebSocketMessage(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {

    // 关闭链路的指令
    if(msg instanceof CloseWebSocketFrame) {
      handshaker.close(ctx.channel(),((CloseWebSocketFrame) msg).retain());
    }
    // 如果是ping指令 返回pong
//    if(msg instanceof PingWebSocketFrame) {
//      ctx.channel().write(new PongWebSocketFrame(msg.content().retain()));
//      return;
//    }
    // 如果是文本消息
    else if(msg instanceof TextWebSocketFrame) {
      // 返回应答消息
      String request = ((TextWebSocketFrame) msg).text();
      System.out.println("服务端接收到信息:" + request);
      TextWebSocketFrame tws = new TextWebSocketFrame("服务端推送："
              + ctx.channel().id() + "说 ：" + request);
      ctx.channel().writeAndFlush(tws);
      // 群发
      // ChannelGroupExecutor.send2All(tws);
    }
    // 如果是二进制
    else if(msg instanceof BinaryWebSocketFrame) {
      ByteBuf content = ((WebSocketFrame) msg).content();
//      MessageDecoder messageDecoder = new MessageDecoder(ConstantValue.MESSAGE_CODEC_MAX_FRAME_LENGTH,
//              ConstantValue.MESSAGE_CODEC_LENGTH_FIELD_LENGTH, ConstantValue.MESSAGE_CODEC_LENGTH_FIELD_OFFSET,
//              ConstantValue.MESSAGE_CODEC_LENGTH_ADJUSTMENT, ConstantValue.MESSAGE_CODEC_INITIAL_BYTES_TO_STRIP, false);
//      StringMessage message = (StringMessage) messageDecoder.decode(ctx, content);
//      // WebSocket接入
//      listener.channelRead(ctx,message);
      // protobuf模式



    }
    else  if (msg instanceof PingWebSocketFrame) {
      ctx.write(new PongWebSocketFrame(msg.content().retain()));
      return;
    }
  }

  @Override
  public void channelActive(ChannelHandlerContext ctx) {
    listener.onConnected(ctx);
  }

  @Override
  public void channelInactive(ChannelHandlerContext ctx) {
    listener.onDisconnected(ctx);
  }

  @Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable throwable) {
    listener.onExceptionCaught(ctx, throwable);
  }

}
